package at.fhhagenberg.mcm09.elevator.ui;

import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.net.MalformedURLException;
import java.rmi.Naming;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
import java.util.EventListener;
import java.util.Iterator;
import java.util.Observable;
import java.util.Observer;
import java.util.Queue;
import java.util.Vector;

import javax.swing.ButtonGroup;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.ListSelectionModel;
import javax.swing.border.EtchedBorder;
import javax.swing.border.TitledBorder;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;

import sqelevator.IElevator;
import at.fhhagenberg.mcm09.elevator.control.ElevatorAdapter;
import at.fhhagenberg.mcm09.elevator.control.ElevatorControl;
import at.fhhagenberg.mcm09.elevator.control.EventGenerator;
import at.fhhagenberg.mcm09.elevator.control.ElevatorControl.ControlMode;
import at.fhhagenberg.mcm09.elevator.model.CallRequest;
import at.fhhagenberg.mcm09.elevator.model.InfoModel;
import at.fhhagenberg.mcm09.elevator.model.RequestModel;
import at.fhhagenberg.mcm09.elevator.model.StopRequest;

/**
*
* @class  ElevatorGUI
* @author Christoph Reisinger mcm08010
*/
public class ElevatorGUI extends WindowAdapter implements EventListener, ActionListener, ListSelectionListener, Observer{

	private static IElevator m_IElevator;
	private ElevatorControl m_elevatorCtr;
	private Vector<Object> m_controlRadiobuttonVector;
	private Vector<Object> m_callRadiobuttonVector;
	private Vector<Object> m_stopRadiobuttonVector;
	private Vector<Object> m_floorLabelVector;
	
	private Queue<StopRequest> m_requestQueue;
	private Iterator m_queueIterator;
	
	private int m_floorQuantity;
	
	/* define Components */
	// Frame
	private JFrame m_elevatorFrame;
	
	// Panels
	private JPanel m_infoPanel;
	private JPanel m_floorPanel;
	private JPanel m_controlPanel;
	private JPanel m_controlPanelLeftSide;
	private JPanel m_controlPanelRightSide;
	
	// Labels
	private JLabel m_positionLabel;
	private JLabel m_positionValueLabel;
	private JLabel m_directionLabel;
	private JLabel m_directionValueLabel;
	private JLabel m_weightLabel;
	private JLabel m_weightValueLabel;
	private JLabel m_speedLabel;
	private JLabel m_speedValueLabel;
	private JLabel m_doorStatusLabel;
	private JLabel m_doorStatusValueLabel;
	private JLabel m_targetFloorLabel;
	private JLabel m_targetFloorValueLabel;
	
	private JLabel m_floorLabel;
	private JLabel m_floorCallLabel;
	private JLabel m_floorStopRequestLabel;
	private JLabel m_floor9Label;
	private JLabel m_floor8Label;
	private JLabel m_floor7Label;
	private JLabel m_floor6Label;
	private JLabel m_floor5Label;
	private JLabel m_floor4Label;
	private JLabel m_floor3Label;
	private JLabel m_floor2Label;
	private JLabel m_floor1Label;
	private JLabel m_floor0Label;

	private JLabel m_manualControlLabel;
	
	// RadioButtons
	private JRadioButton m_call9Button;
	private JRadioButton m_call8Button;
	private JRadioButton m_call7Button;
	private JRadioButton m_call6Button;
	private JRadioButton m_call5Button;
	private JRadioButton m_call4Button;
	private JRadioButton m_call3Button;
	private JRadioButton m_call2Button;
	private JRadioButton m_call1Button;
	private JRadioButton m_call0Button;

	private JRadioButton m_stopRequest9Button;
	private JRadioButton m_stopRequest8Button;
	private JRadioButton m_stopRequest7Button;
	private JRadioButton m_stopRequest6Button;
	private JRadioButton m_stopRequest5Button;
	private JRadioButton m_stopRequest4Button;
	private JRadioButton m_stopRequest3Button;
	private JRadioButton m_stopRequest2Button;
	private JRadioButton m_stopRequest1Button;
	private JRadioButton m_stopRequest0Button;
	
	private JRadioButton m_manualControl9Button;
	private JRadioButton m_manualControl8Button;
	private JRadioButton m_manualControl7Button;
	private JRadioButton m_manualControl6Button;
	private JRadioButton m_manualControl5Button;
	private JRadioButton m_manualControl4Button;
	private JRadioButton m_manualControl3Button;
	private JRadioButton m_manualControl2Button;
	private JRadioButton m_manualControl1Button;
	private JRadioButton m_manualControl0Button;
	
	// Lists
	private JList m_controlChoiceList;	
	
	// ButtonGroup
	private ButtonGroup m_buttonGroup;
		
	// String Array
	private String[] m_controlChoices = {"Automatic", "Manual"};		
	
	/**
	 * Constructer
	 * 
	 * @param _ctr		instance of ElevatorControl
	 * @param _floors	number of floors(1...10)
	 */
	public ElevatorGUI(ElevatorControl _ctr, int _floors){
		m_floorQuantity = _floors;
		m_elevatorCtr =_ctr;
		initComponents();
		buildGUI();
	}
	
	/**
	 *  init GUI Components	
	 */
	private void initComponents(){
		// set Control Mode
		m_elevatorCtr.setControlMode(ControlMode.AUTOMATIC);
		
		// init component Vectors
		m_controlRadiobuttonVector = new Vector<Object>();
		m_callRadiobuttonVector = new Vector<Object>();;
		m_stopRadiobuttonVector = new Vector<Object>();
		m_floorLabelVector = new Vector<Object>();
		
		// init Frame
		m_elevatorFrame = new JFrame();
		
		// init Panels
		m_infoPanel = new JPanel();
		m_floorPanel = new JPanel();
		m_controlPanel = new JPanel();
		m_controlPanelLeftSide = new JPanel();
		m_controlPanelRightSide = new JPanel();
				
		// init info Text Labels
		m_positionLabel = new JLabel("Position: "); 
		m_positionValueLabel = new JLabel("0");
		m_directionLabel = new JLabel("Direction: "); 
		m_directionValueLabel = new JLabel("-");
		m_weightLabel = new JLabel("Weight: "); 
		m_weightValueLabel = new JLabel("0 lbs");
		m_speedLabel = new JLabel("Speed: ");
		m_speedValueLabel = new JLabel("0 m/s");
		m_doorStatusLabel = new JLabel("Door Status: ");
		m_doorStatusValueLabel = new JLabel("closed");
		m_targetFloorLabel = new JLabel("Target Floor: ");	
		m_targetFloorValueLabel = new JLabel("-");
		
		// init floor text labels
		m_floorLabel = new JLabel("Floor");
		m_floorCallLabel = new JLabel("Call");
		m_floorStopRequestLabel = new JLabel("Stop");
		m_floor9Label = new JLabel("   9");
		m_floor8Label = new JLabel("   8");
		m_floor7Label = new JLabel("   7");
		m_floor6Label = new JLabel("   6");
		m_floor5Label = new JLabel("   5");
		m_floor4Label = new JLabel("   4");
		m_floor3Label = new JLabel("   3");
		m_floor2Label = new JLabel("   2");
		m_floor1Label = new JLabel("   1");
		m_floor0Label = new JLabel("   0");
		
		m_floorLabelVector.add(m_floor0Label);
		m_floorLabelVector.add(m_floor1Label);
		m_floorLabelVector.add(m_floor2Label);
		m_floorLabelVector.add(m_floor3Label);
		m_floorLabelVector.add(m_floor4Label);
		m_floorLabelVector.add(m_floor5Label);
		m_floorLabelVector.add(m_floor6Label);
		m_floorLabelVector.add(m_floor7Label);
		m_floorLabelVector.add(m_floor8Label);
		m_floorLabelVector.add(m_floor9Label);
		
		// init control Labels
		m_manualControlLabel = new JLabel("Target Floor");
		
		// RadioButtons
		m_call9Button = new JRadioButton();
		m_call9Button.setEnabled(false);
		m_call8Button = new JRadioButton();
		m_call8Button.setEnabled(false);
		m_call7Button = new JRadioButton();
		m_call7Button.setEnabled(false);
		m_call6Button = new JRadioButton();
		m_call6Button.setEnabled(false);
		m_call5Button = new JRadioButton();
		m_call5Button.setEnabled(false);
		m_call4Button = new JRadioButton();
		m_call4Button.setEnabled(false);
		m_call3Button = new JRadioButton();
		m_call3Button.setEnabled(false);
		m_call2Button = new JRadioButton();
		m_call2Button.setEnabled(false);
		m_call1Button = new JRadioButton();
		m_call1Button.setEnabled(false);
		m_call0Button = new JRadioButton();	
		m_call0Button.setEnabled(false);
		
		// put the call RadioButtons into the component Vector
		m_callRadiobuttonVector.add(m_call0Button);
		m_callRadiobuttonVector.add(m_call1Button);
		m_callRadiobuttonVector.add(m_call2Button);
		m_callRadiobuttonVector.add(m_call3Button);
		m_callRadiobuttonVector.add(m_call4Button);
		m_callRadiobuttonVector.add(m_call5Button);
		m_callRadiobuttonVector.add(m_call6Button);
		m_callRadiobuttonVector.add(m_call7Button);
		m_callRadiobuttonVector.add(m_call8Button);
		m_callRadiobuttonVector.add(m_call9Button);

		m_stopRequest9Button = new JRadioButton();
		m_stopRequest9Button.setEnabled(false);
		m_stopRequest8Button = new JRadioButton();
		m_stopRequest8Button.setEnabled(false);
		m_stopRequest7Button = new JRadioButton();
		m_stopRequest7Button.setEnabled(false);
		m_stopRequest6Button = new JRadioButton();
		m_stopRequest6Button.setEnabled(false);
		m_stopRequest5Button = new JRadioButton();
		m_stopRequest5Button.setEnabled(false);
		m_stopRequest4Button = new JRadioButton();
		m_stopRequest4Button.setEnabled(false);
		m_stopRequest3Button = new JRadioButton();
		m_stopRequest3Button.setEnabled(false);
		m_stopRequest2Button = new JRadioButton();
		m_stopRequest2Button.setEnabled(false);
		m_stopRequest1Button = new JRadioButton();
		m_stopRequest1Button.setEnabled(false);
		m_stopRequest0Button = new JRadioButton();
		m_stopRequest0Button.setEnabled(false);	
		
		// put the stop RadioButtons into the component Vector
		m_stopRadiobuttonVector.add(m_stopRequest0Button);
		m_stopRadiobuttonVector.add(m_stopRequest1Button);
		m_stopRadiobuttonVector.add(m_stopRequest2Button);
		m_stopRadiobuttonVector.add(m_stopRequest3Button);
		m_stopRadiobuttonVector.add(m_stopRequest4Button);
		m_stopRadiobuttonVector.add(m_stopRequest5Button);
		m_stopRadiobuttonVector.add(m_stopRequest6Button);
		m_stopRadiobuttonVector.add(m_stopRequest7Button);
		m_stopRadiobuttonVector.add(m_stopRequest8Button);
		m_stopRadiobuttonVector.add(m_stopRequest9Button);
		
		m_buttonGroup = new ButtonGroup();
		m_manualControl9Button = new JRadioButton();
		m_manualControl9Button.addActionListener(this);
		m_buttonGroup.add(m_manualControl9Button);
		m_manualControl8Button = new JRadioButton();
		m_manualControl8Button.addActionListener(this);
		m_buttonGroup.add(m_manualControl8Button);
		m_manualControl7Button = new JRadioButton();
		m_manualControl7Button.addActionListener(this);
		m_buttonGroup.add(m_manualControl7Button);
		m_manualControl6Button = new JRadioButton();
		m_manualControl6Button.addActionListener(this);
		m_buttonGroup.add(m_manualControl6Button);
		m_manualControl5Button = new JRadioButton();
		m_manualControl5Button.addActionListener(this);
		m_buttonGroup.add(m_manualControl5Button);
		m_manualControl4Button = new JRadioButton();
		m_manualControl4Button.addActionListener(this);
		m_buttonGroup.add(m_manualControl4Button);
		m_manualControl3Button = new JRadioButton();
		m_manualControl3Button.addActionListener(this);
		m_buttonGroup.add(m_manualControl3Button);
		m_manualControl2Button = new JRadioButton();
		m_manualControl2Button.addActionListener(this);
		m_buttonGroup.add(m_manualControl2Button);
		m_manualControl1Button = new JRadioButton();
		m_manualControl1Button.addActionListener(this);
		m_buttonGroup.add(m_manualControl1Button);
		m_manualControl0Button = new JRadioButton();
		m_manualControl0Button.addActionListener(this);
		m_buttonGroup.add(m_manualControl0Button);	
		
		// put the control RadioButtons into the component Vector
		m_controlRadiobuttonVector.add(m_manualControl0Button);
		m_controlRadiobuttonVector.add(m_manualControl1Button);
		m_controlRadiobuttonVector.add(m_manualControl2Button);
		m_controlRadiobuttonVector.add(m_manualControl3Button);
		m_controlRadiobuttonVector.add(m_manualControl4Button);
		m_controlRadiobuttonVector.add(m_manualControl5Button);
		m_controlRadiobuttonVector.add(m_manualControl6Button);
		m_controlRadiobuttonVector.add(m_manualControl7Button);
		m_controlRadiobuttonVector.add(m_manualControl8Button);
		m_controlRadiobuttonVector.add(m_manualControl9Button);
		
		// create Lists
		m_controlChoiceList = new JList(m_controlChoices);
		m_controlChoiceList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
		m_controlChoiceList.setLayoutOrientation(JList.VERTICAL_WRAP);
		m_controlChoiceList.setVisibleRowCount(2);
		m_controlChoiceList.setBorder(new TitledBorder(new EtchedBorder(), "Setting")); 
		m_controlChoiceList.addListSelectionListener(this);
		m_controlChoiceList.setSelectedIndex(0);
	}
	
	/**
	 *  build GUI 	
	 */
	public void buildGUI() {
		m_elevatorFrame.setSize(600,250);
		m_elevatorFrame.setMinimumSize(new Dimension(500,200));
		m_elevatorFrame.addWindowListener(this);		
		m_elevatorFrame.setTitle("Elevator Control Center");
		m_elevatorFrame.setLayout(new GridLayout(1,3));
		
		// configure infoPanel
		m_infoPanel.setLayout(new GridLayout(6,2));          
		m_infoPanel.setBorder(new TitledBorder(new EtchedBorder(), "Elevator Information")); 
		
		// configure floorPanel
		m_floorPanel.setLayout(new GridLayout(m_floorQuantity+1,3));        
		m_floorPanel.setBorder(new TitledBorder(new EtchedBorder(), "Floor Overview")); 		
		
		// configure controlPanel
		m_controlPanel.setLayout(new GridLayout(1,2));	
		m_controlPanel.setBorder(new TitledBorder(new EtchedBorder(), "Elevator Control")); 
		
		// configure controlPanel 
		m_controlPanelLeftSide.setLayout(new GridLayout(m_floorQuantity+1,0));
        
        // add Components to infoPanel
		m_infoPanel.add(m_positionLabel);
		m_infoPanel.add(m_positionValueLabel);
		m_infoPanel.add(m_directionLabel);
		m_infoPanel.add(m_directionValueLabel);
		m_infoPanel.add(m_weightLabel);
		m_infoPanel.add(m_weightValueLabel);
		m_infoPanel.add(m_speedLabel);
		m_infoPanel.add(m_speedValueLabel);
		m_infoPanel.add(m_doorStatusLabel);
		m_infoPanel.add(m_doorStatusValueLabel);
		m_infoPanel.add(m_targetFloorLabel);
		m_infoPanel.add(m_targetFloorValueLabel);
		
		// add Components to floorPanel		
		m_floorPanel.add(m_floorLabel);
		m_floorPanel.add(m_floorCallLabel);
		m_floorPanel.add(m_floorStopRequestLabel);
		for(int idx=m_floorQuantity-1; idx>=0; idx--){
			// add Labels from LabelVector
			JLabel label = (JLabel)m_floorLabelVector.elementAt(idx);
			m_floorPanel.add(label);
			// add CallButtons from m_callRadiobuttonVector
			JRadioButton rbutton = (JRadioButton)m_callRadiobuttonVector.elementAt(idx);
			m_floorPanel.add(rbutton);
			// add StopButtons from m_stopRadiobuttonVector
			rbutton = (JRadioButton)m_stopRadiobuttonVector.elementAt(idx);
			m_floorPanel.add(rbutton);
		}
		
		// add Components to left controlPanel		
		m_controlPanelLeftSide.add(m_manualControlLabel);
		for(int idx=m_floorQuantity-1; idx>=0; idx--){
			JRadioButton rbutton = (JRadioButton)m_controlRadiobuttonVector.elementAt(idx);
			m_controlPanelLeftSide.add(rbutton);
		}
		
		// add Components to left controlPanel
		m_controlPanelRightSide.add(m_controlChoiceList); 
		
		// build controlPanel with left and right side
		m_controlPanel.add(m_controlPanelLeftSide);
		m_controlPanel.add(m_controlPanelRightSide);
		
		// build elevatorFrame
		m_elevatorFrame.add(m_infoPanel);
        m_elevatorFrame.add(m_floorPanel);
        m_elevatorFrame.add(m_controlPanel);
        m_elevatorFrame.setVisible(true);		
	}
	
	@Override
	public void actionPerformed(ActionEvent _e) {   
		
		// deselect all previously selected call RadioButtons
		clearRequest();		
				
		// check which manual control Radiobutton is selected
		for(int idx=m_floorQuantity-1; idx>=0; idx--){
			JRadioButton rbutton = (JRadioButton)m_controlRadiobuttonVector.elementAt(idx);
			if (rbutton.isSelected()){				
	        	//setManualTargetFloor(idx); // set Target Floor
	        	//setCallRequestFloor(idx); // set CallRequest
				setManualTarget(idx);
	        }
		}
	}		
	
	/**
	* close Window
	*/
    public void windowClosing(WindowEvent _e) {
        System.exit(0);
    }

	@Override
	public void valueChanged(ListSelectionEvent _e) {		
			
		if(_e.getValueIsAdjusting() == false){
			if (m_controlChoiceList.getSelectedIndex() == 0) { 
				
				// deselect all call RadioButtons
				clearRequest();
				
				// Change mode to AUTOMATIC
				m_elevatorCtr.setControlMode(ControlMode.AUTOMATIC);
				m_targetFloorValueLabel.setText("-");
				
				// disable all manual control Radiobuttons
				for(int idx=m_floorQuantity-1; idx>=0; idx--){
					JRadioButton rbutton = (JRadioButton)m_controlRadiobuttonVector.elementAt(idx);
					rbutton.setEnabled(false);
				}
				m_buttonGroup.clearSelection();
            } // Automatic Mode
			else if (m_controlChoiceList.getSelectedIndex() == 1) { 
				
				// Change mode to MANUAL
				m_elevatorCtr.setControlMode(ControlMode.MANUAL);
				
				// enable all manual control Radiobuttons
				for(int idx=m_floorQuantity-1; idx>=0; idx--){
					JRadioButton rbutton = (JRadioButton)m_controlRadiobuttonVector.elementAt(idx);
					rbutton.setEnabled(true);
				}
            } // Manual Mode 
			else {
            }
		}		
	}
	private void setPosition(int _pos){
		m_positionValueLabel.setText(Integer.toString(_pos));
	}
	
	private void setDirection(int _direction){
		if(_direction == 0){
			m_directionValueLabel.setText("Up");
		}
		else if(_direction == 1){
			m_directionValueLabel.setText("Down");
		}
		else if(_direction == 2){
			m_directionValueLabel.setText("Hold");
		}
	}
	
	private void setWeight(float _weight){
		m_weightValueLabel.setText(Float.toString(_weight));
	}
	
	private void setSpeed(float _speed){
		m_speedValueLabel.setText(Float.toString(_speed));
	}
	
	private void setDoorStatus(boolean _door){
		if(_door){
			m_doorStatusValueLabel.setText("Closed");
		}
		else if(!_door){
			m_doorStatusValueLabel.setText("Open");
		}		
	}
	
	private void setTargetFloor(int _targetFloor){
		m_targetFloorValueLabel.setText(Integer.toString(_targetFloor));
		//m_elevatorCtr.setCommand(new StopRequest(_targetFloor));
	}
	
	private void setManualTarget(int _manualTarget){
		m_elevatorCtr.setCommand(new StopRequest(_manualTarget));		
	}
	
	private void setCallRequestFloor(int _callFloor){		
		JRadioButton rbutton = (JRadioButton)m_callRadiobuttonVector.elementAt(_callFloor);
		rbutton.setSelected(true);
	}
	
	private void setStopRequestFloor(int _stopFloor){
		JRadioButton rbutton = (JRadioButton)m_stopRadiobuttonVector.elementAt(_stopFloor);
		rbutton.setSelected(true);
	}
	
	private void clearRequest(){
		// deselect all call RadioButtons
		for(int idx=m_floorQuantity-1; idx>=0; idx--){
			// clear Call Requests in the UI
			JRadioButton rbutton = (JRadioButton)m_callRadiobuttonVector.elementAt(idx);
			rbutton.setSelected(false);
			// clear Stop Requests in the UI
			rbutton = (JRadioButton)m_stopRadiobuttonVector.elementAt(idx);
			rbutton.setSelected(false);
		}
	}	

	@Override
	public void update(Observable _o, Object _model) {		
		
		if (_model instanceof InfoModel){
			// show Speed
	        setSpeed(((InfoModel) _model).getSpeed());
	        // show load
	        setWeight(((InfoModel) _model).getLoad());
	        // show Direction 0 up; 1 down; 2 hold
	        setDirection(((InfoModel) _model).isUpward());
	        // show Door Status
	        setDoorStatus(((InfoModel) _model).isDoorClosed());	    
	        // show Position
	        setPosition(((InfoModel) _model).getPos());
	    }	
		else if(_model instanceof RequestModel){
			// Clear all Requests in the UI
			clearRequest();
			m_requestQueue = ((RequestModel) _model).getStopQueue();
			m_queueIterator =  m_requestQueue.iterator();
			
			while(m_queueIterator.hasNext())
	        {	
				Object o = m_queueIterator.next();
				if( o instanceof CallRequest){
					CallRequest r = (CallRequest)o;	
					// show Call Requests in the UI
					setCallRequestFloor(r.getTargetFloor());
				}
				else if(o instanceof StopRequest){
					StopRequest r = (StopRequest)o;
					// show Stop Requests in the UI
					setStopRequestFloor(r.getTargetFloor());					
				}
	        }	
			// show target Floor
			setTargetFloor(m_elevatorCtr.getTargetFloor());
		}
	}
    
	public static void main(String[] args) throws RemoteException {

		try {
			IElevator controller = (IElevator) Naming.lookup("rmi://localhost/ElevatorSim");
			ElevatorAdapter adapter = new ElevatorAdapter(controller);			
			EventGenerator eventG =  new EventGenerator(adapter);	
			ElevatorControl ctr = new ElevatorControl(controller, adapter, eventG);
			//ElevatorGUI gui = new ElevatorGUI(ctr, 10);	
			ElevatorGUI gui = new ElevatorGUI(ctr, adapter.getFloorNum());	
			eventG.addObserver(gui);
			eventG.run();
		} catch (MalformedURLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (NotBoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
	}
}
